// Container.h
// Created by Limou on 24-9-13.
// 描述了一个子项组件(选择框部件+名称按钮部件+头像按钮部件)
// 描述了一个滚动区组件(由上述子项组件组成的滚动区域)

#ifndef FRONTEND_CONTAINER_HPP
#define FRONTEND_CONTAINER_HPP

#include <QWidget>
#include <QCheckBox>
#include <QPushButton>
#include <QScrollArea>
#include <QHBoxLayout>
#include <QStyleOption>
#include <QScrollBar>
#include <QMouseEvent>
#include <QPainter>
#include "../../common/Common.hpp"
#include "../../model/UserModel.hpp"

// >>> class ContainerItem begin: 描述一个滚动区子项的部件 >>>
namespace chat_system::subassembly::ChooseFriendDialog {
    class ContainerItem : public QWidget {
    Q_OBJECT

    private:
        // 组件
        QCheckBox *checkBox_; // 选择框部件
        QPushButton *avatarBtn_; // 用户按钮部件
        QPushButton *nameBtn_; // 用户名按钮部件
        // 数据
        model::UserModel user_; // 用户数据
        bool checked_; // 选择框是否被选中

    public:
        // 空构造方法
        explicit ContainerItem() {};

        // 构造方法
        explicit ContainerItem(
            const model::UserModel &user,
            const bool &checked,
            QWidget *parent = nullptr
        )
        : QWidget(parent)
        , checkBox_(new QCheckBox(this)) // TODO: 先这样, 以后再来修改为对象树
        , avatarBtn_(new QPushButton(this))
        , nameBtn_(new QPushButton(this))
        , user_(user)
        , checked_(checked) {
            this->setElementStyle();  // 设置组件风格
            this->setElementLayout(); // 设置组件布局
            this->setElementSignalSlot(); // 设置信号槽
        }

        // 析构方法
        ~ContainerItem() override = default;

        // 检查当前项的是否被选中
        bool isChecked() {
            return checkBox_->isChecked();
        }

        // 获取子项用户数据方法
        model::UserModel getUser() {
            return user_;
        }

    signals:

        // 自定义点击信号
        void clicked(); // 当点击本组件的非子组件的地方时会触发点击信号
        void confirm(); // 当上面点击信号被触发后, 并且本组件确认时, 就会进一步触发这个信号
        void cancel(); // 当上面点击信号被触发后, 并且本组件取消时, 就会进一步触发这个信号

    protected:
        // 重写绘制事件(以支持本组件适用 QSS)
        void paintEvent(QPaintEvent *event) override { // 必须重写这个方法才能使得 this 支持 qss
            (void) event; // 避免警告
            QStyleOption opt; // 创建可以存储绘制部件时所需的各种信息的对象
            opt.initFrom(this); // 将当前部件的属性初始化到 opt 对象中
            QPainter p(this); // 创建了一个 QPainter 对象 p 并将其与当前部件关联
            style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); // TODO: ? 老实说, 这里没看懂，以后研究叭...
        }

        // 重写鼠标事件(以支持左键点击本组件触发自定义的 clicked 信号)
        void mousePressEvent(QMouseEvent *event) override {
            QWidget::mousePressEvent(event); // 调用父类的 mousePressEvent 以确保其他鼠标事件正常处理

            if (event->button() == Qt::LeftButton) { // 当本组件内有鼠标左键事件发生 NOTE: 注意范围是本组件, 不包含叠在父组件上面的子组件...
                emit this->clicked(); // 就向外发送点击信号
            }
        }

    private:
        // 设置组件风格
        void setElementStyle() {
            // 提前设置尺寸
            QSize size(50, 50);

            // 设置本部件
            this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
            this->setFixedHeight(50);
            this->setFixedWidth(750 / 2 - 100);
            this->setStyleSheet("QWidget { background-color: white; }");

            // 设置选择框部件
            checkBox_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            checkBox_->setFixedSize(size);
            checkBox_->setCheckState(checked_ ? Qt::Checked : Qt::Unchecked);
            if (checked_) { // 如果一开始就选中了, 这里也让背景色改一下
                this->setStyleSheet("QWidget { background-color: rgb(243, 243, 243); }");
            }

            // 设置用户按钮部件
            avatarBtn_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            avatarBtn_->setFixedSize(size);
            avatarBtn_->setIconSize(QSize(40, 40));
            const QIcon &avatarBtnIcon(user_.getUserAvatarIco());
            if (avatarBtnIcon.isNull()) {
                common::Tools::getInstance()->getLogger()->warn("ContainerItem(): avatarBtnIcon is null.");
            }
            avatarBtn_->setIcon(avatarBtnIcon);
            avatarBtn_->setStyleSheet("QPushButton { border: none; }");

            // 设置用户名按钮部件
            nameBtn_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            nameBtn_->setFixedHeight(50);
            nameBtn_->setText(user_.getUserNickName());
            nameBtn_->setStyleSheet("QPushButton { border: none; color: black; }");
        }

        // 设置组件布局
        void setElementLayout() {
            auto selfLayout = new QHBoxLayout();
            selfLayout->setSpacing(0);
            selfLayout->setContentsMargins(10, 0, 10, 0);

            selfLayout->addWidget(checkBox_, 0, Qt::AlignCenter);
            selfLayout->addWidget(avatarBtn_, 0, Qt::AlignCenter);
            selfLayout->addWidget(nameBtn_, 0, Qt::AlignLeft);

            selfLayout->addStretch(); // 添加伸缩项，使右侧留空

            this->setLayout(selfLayout);
        }

        // 设置信号槽
        void setElementSignalSlot() {
            auto switchCheck = [this](){
                bool isChecked = this->isChecked(); // 获取当前状态
                checkBox_->setChecked(!isChecked); // 切换复选框状态
            };

            // 当点击整个组件时, 切换复选框状态, 并且发送信号
            connect(this, &ContainerItem::clicked, this, switchCheck);

            // 当点击 avatarBtn_ 时, 切换复选框状态, 并且发送信号
            connect(avatarBtn_, &QPushButton::clicked, this, switchCheck);

            // 当点击 nameBtn_ 时, 切换复选框状态, 并且发送信号
            connect(nameBtn_, &QPushButton::clicked, this, switchCheck);

            // 当 checkBox_ 的状态改变时, 发送点击信号
            connect(checkBox_, &QCheckBox::stateChanged, this, [this]() {
                bool isChecked = this->isChecked(); // 获取当前状态
                if (isChecked == true) {
                    common::Tools::getInstance()->getLogger()->trace("{0}-{1}-setElementSignalSlot(): emit confirm [O]", __FILE__, __LINE__);
                    emit this->confirm(); // 表示本组件确认
                }
                else {
                    common::Tools::getInstance()->getLogger()->trace("{0}-{1}-setElementSignalSlot(): emit cancel [X]", __FILE__, __LINE__);
                    emit this->cancel(); // 表示本组件取消
                }
            });

            // 当复选框状态改变时，修改选中和未选中时的样式
            connect(checkBox_, &QCheckBox::stateChanged, this, [this](int state) {
                if (state == Qt::Checked) {
                    this->setStyleSheet("QWidget { background-color: rgb(243, 243, 243); }");
                } else {
                    this->setStyleSheet("QWidget { background-color: white; }");
                }
            });
        }
    };
} // namespace chat_system::subassembly::ChooseFriendDialog end
// <<< class ContainerItem end <<<

// >>> class Container begin: 描述一个滚动区域的部件 >>>
namespace chat_system::subassembly::ChooseFriendDialog {
    class Container : public QScrollArea {
    Q_OBJECT
    private:
        QWidget *OriginalContainer_; // 滚动区域内部可变长的 QWidget 部件

    public:
        // 构造方法
        explicit Container(QWidget *parent = nullptr)
        : QScrollArea(parent)
        , OriginalContainer_(new QWidget(this)) {
    this->setElement(); // 设置组件
    this->setElementStyle(); // 设置组件样式
    this->setElementLayout(); // 设置组件布局
    this->setElementSignalSlot(); // 设置信号槽
}

        // 析构方法
        ~Container() override = default;

        // 获取滚动区域内部的 QWidget 部件
        QWidget* getOriginalContainer() {
            return OriginalContainer_;
        }

        // 添加子项方法
        void addTailItem(const model::UserModel& user, const bool &checked) {
            auto containerItem = new ContainerItem(user, checked, OriginalContainer_);
            common::Tools::getInstance()->getLogger()->trace("{0}-{1}-Container::addTailItem(const model::UserModel &user, const bool &checked): new ContainerItem = {2}", __FILE__, __LINE__, std::to_string(reinterpret_cast<uintptr_t>(containerItem)));
            this->addTailItem(containerItem); // 调用重载版本的 addTailItem()
        }
        void addTailItem(ContainerItem* containerItem) { // TODO: 可能需要加上 const
            common::Tools::getInstance()->getLogger()->trace("{0}-{1}-Container::addTailItem(ContainerItem* containerItem: get containerItem pointer = {2}", __FILE__, __LINE__, std::to_string(reinterpret_cast<uintptr_t>(containerItem)));
            // 检查 containerItem 是否为空
            if (containerItem == nullptr) {
                common::Tools::getInstance()->getLogger()->error("addTailItem(ContainerItem* containerItem): Cannot add a null item.");
                return;
            }

            // 添加 containerItem 到布局管理器中
            auto layout = dynamic_cast<QVBoxLayout*>(OriginalContainer_->layout());
            if (!layout) {
                common::Tools::getInstance()->getLogger()->error("addTailItem(ContainerItem* containerItem): Layout cast failed.");
                return; // 在转换失败时及时返回，避免后续操作发生错误
            }
            layout->addWidget(containerItem);

            // 连接信号槽, 如果该子项发送了 ContainerItem::confirm 确认信号, 就发送 Container::confirm 信号, 把该子项指针传递出去(交给别的组件去添加)
            connect(containerItem, &ContainerItem::confirm, this, [containerItem, this]() {
                common::Tools::getInstance()->getLogger()->trace("{0}-{1}-Container::addTailItem(ContainerItem* containerItem): emit cancel [X]", __FILE__, __LINE__);
                emit this->confirm(containerItem);
            });

            // 连接信号槽, 如果该子项发送了 ContainerItem::cancel 取消信号, 就发送 Container::cancel 信号, 把该子项指针传递出去(交给别的组件去删除)
            connect(containerItem, &ContainerItem::cancel, this, [containerItem, this]() {
                common::Tools::getInstance()->getLogger()->trace("{0}-{1}-Container::addTailItem(ContainerItem* containerItem): emit confirm [O]", __FILE__, __LINE__);
                emit this->cancel(containerItem);
            });
        }

        // 移动子项方法
        void moveItem(ContainerItem* containerItem) { // TODO: 可能需要加上 const
            common::Tools::getInstance()->getLogger()->trace("{0}-{1}-Container::moveItem(ContainerItem* containerItem: move containerItem pointer = {2}", __FILE__, __LINE__, std::to_string(reinterpret_cast<uintptr_t>(containerItem)));

            // 检查 containerItem 是否为空
            if (containerItem == nullptr) {
                common::Tools::getInstance()->getLogger()->error("addTailItem(): Cannot add a null item.");
                return;
            }

            // 添加 containerItem 到布局管理器中
            auto layout = dynamic_cast<QVBoxLayout*>(OriginalContainer_->layout());
            if (!layout) {
                common::Tools::getInstance()->getLogger()->error("addTailItem(): Layout cast failed.");
                return; // 在转换失败时及时返回，避免后续操作发生错误
            }

            layout->addWidget(containerItem);
        }

    signals:
        // 自定义点击信号
        void confirm(ContainerItem* ontainerItem); // 当上面点击信号被触发后, 并且确认时, 就会进一步触发这个信号(并且把自己发送出去方便后续代码进行添加)
        void cancel(ContainerItem* containerItem); // 当上面点击信号被触发后, 并且取消时, 就会进一步触发这个信号

    private:
        // 设置组件
        void setElement() {
            // 设置本部件
            this->setFixedSize(QSize(750 / 2 - 100, 550 - 125));

            // 设置滚动区域部件
            this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
            this->setWidgetResizable(true);

            this->setWidget(OriginalContainer_); // TODO: 这里应该就会导致 OriginalContainer_ 变成 SessionFriendArea 对象
        }

        // 设置组件样式
        void setElementStyle() {
            this->setStyleSheet("QScrollArea { border: none;}");
            this->verticalScrollBar()->setStyleSheet( // 设置垂直滚动条
                    "QScrollBar:vertical {"
                    "width: 5px;"
                    "background-color: transparent;"
                    "}"
                    "QScrollBar::handle:vertical {"
                    "background: rgb(46, 46, 46);"
                    "}"
                    "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {"
                    "background: transparent;"
                    "}"
            );
            this->horizontalScrollBar()->setStyleSheet( // 设置水平滚动条
                    "QScrollBar:horizontal {"
                    "height: 0px"
                    "}"
            );

            // 设置滚动区域内部可变长的 QWidget 部件
            OriginalContainer_->setStyleSheet("QWidget { border: none; } ");
        }

        // 设置组件布局
        void setElementLayout() {
            // 设置布局管理器
            auto layout = new QVBoxLayout();
            layout->setSpacing(0);
            layout->setContentsMargins(0, 0, 0, 0);
            layout->setAlignment(Qt::AlignTop); // 设置布局管理器的对齐方式
            OriginalContainer_->setLayout(layout);
        }

        // 设置信号槽方法
        void setElementSignalSlot() {
            // TODO: 暂时还没有什么可以做的
        }
    };
}
// <<< class Container end <<<

#endif // FRONTEND_CONTAINER_HPP
